Шаг 8 - Рисуем примитивы

Загрузить проект

Немного теории

Мы уже рисовали по панели, помните в 4-м шаге для вывода строки "Hello world!", мы перегружали функцию paint(Graphics g) и использовали для вывода текста в заданной позиции соответствующую функцию из класса Graphics. Такой метод является приемлемым только для AWT - компонент. Для Swing - компонент процедура рисования разбита на три этапа, которые представлены соответственно такими функциями: Два последние из вышеперечисленных методов нельзя ни перегружать, ни вызывать, а вот   paintComponent(Graphics g) перегружать можно, этим мы и воспользуемся.

Главный интерес представляет аргумент этой функции. Класс Graphics является базовым для всех контекстов, которые разрешают рисовать по компоненте. С другой стороны данный класс содержит функции необходимые для рисования, например drawLine, drawString, drawImage и т.д. вместе с вспомогательными для установки текущих шрифта (setFont), цвета линий или текста (setColor) и др.

В сегодняшнем примере предлагаю вспомнить детство - попробуем построить график синусоиды, для вычисления значений которой воспользуемся соответствующим статическим методом класса Math. Рисовать будем по панели, для чего создадим свой класс - потомок JPanel и перегрузим соответствующий метод.

Создаем код

import java.awt.*;
import javax.swing.*;

public class PaintApp extends JFrame
{
 public PaintApp(String title)
 {
 super(title);

    //создадим свою рисующую пенель
 GraphSinPanel grSnPn=new GraphSinPanel();
 grSnPn.setPreferredSize(new Dimension(300,300));

   //установим нашу панель как ContentPane окна приложения
 setContentPane(grSnPn);
 }

 public static void main(String args[])
 {
  PaintApp OurApp = new PaintApp("Graph of sin(x)");
  OurApp.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  OurApp.pack();
  OurApp.setVisible(true);
 }
}

class GraphSinPanel extends JPanel
{
 private int Wth, Hig;
 private int PrevX, PrevY, CurX, CurY;
 private final double Pi=Math.PI;
 private Font curFont;
 private FontMetrics curFontMetrics;
 
 public GraphSinPanel()
 {
  super();

    //задаем фон
  setBackground(Color.black);
  
    //получим текущий шрифт и его метрику
    //это понадобится для определения длины текста  
  curFont=getFont();
  curFontMetrics=getFontMetrics(curFont);
 }

    //две нижеследующие функции мне понадобились для преобразования
    //системы координат (стандартно начало отсчета находится в левом
    //верхнем углу, ось Х идет направо, ось У - вниз). Я выбрал систему 
    //координат с началом в центре и такими диапазонами: -5Pi/2< x < 5Pi/2,
    //-1.5< y <1.5
 private int Convert_X(double x)
 {
  return (int)((Wth/2)+(x/(5*Pi/2))*(Wth/2));
 }
 
 private int Convert_Y(double x)
 {
  return (int)((Hig/2)-(x/(1.5))*(Hig/2));
 }

    //функция - гвоздь программы
 public void paintComponent(Graphics g)
 {
    //вызовем соответствующий родительский метод для отрисовки фона
  super.paintComponent(g);

    //получим размеры области рисования
  Wth=getSize().width;
  Hig=getSize().height;

    //устанавливаем цвет
  g.setColor(Color.white);
  
    //рисуем оси, стрелки и т.д.
  g.drawLine(Convert_X(-5*Pi/2)+5, Convert_Y(0), Convert_X(5*Pi/2)-5, Convert_Y(0));
  g.drawLine(Convert_X(0), Convert_Y(1.5)+5, Convert_X(0), Convert_Y(-1.5)-5);

  g.drawLine(Convert_X(5*Pi/2)-5, Convert_Y(0), Convert_X(5*Pi/2)-15, Convert_Y(0)+3);
  g.drawLine(Convert_X(5*Pi/2)-5, Convert_Y(0), Convert_X(5*Pi/2)-15, Convert_Y(0)-3);
  g.drawLine(Convert_X(0), Convert_Y(1.5)+5, Convert_X(0)-3, Convert_Y(1.5)+15);
  g.drawLine(Convert_X(0), Convert_Y(1.5)+5, Convert_X(0)+3, Convert_Y(1.5)+15);

  
  g.drawLine(Convert_X(-2*Pi), Convert_Y(-0.05), Convert_X(-2*Pi), Convert_Y(0.05));
  g.drawLine(Convert_X(-Pi), Convert_Y(-0.05), Convert_X(-Pi), Convert_Y(0.05));
  g.drawLine(Convert_X(Pi), Convert_Y(-0.05), Convert_X(Pi), Convert_Y(0.05));
  g.drawLine(Convert_X(2*Pi), Convert_Y(-0.05), Convert_X(2*Pi), Convert_Y(0.05));
  g.drawLine(Convert_X(-0.05), Convert_Y(1), Convert_X(0.05), Convert_Y(1));
  g.drawLine(Convert_X(-0.05), Convert_Y(-1), Convert_X(0.05), Convert_Y(-1));
     
  
  g.setColor(Color.green);
  
  PrevX=Convert_X(-2*Pi);
  PrevY=Convert_Y(Math.sin(-2*Pi));
  
  
     //рисуем саму синусоиду...
  for (double delta=(-2*Pi); delta<=(2*Pi); delta+=(4*Pi/200))
  {
   CurX=Convert_X(delta);
   CurY=Convert_Y(Math.sin(delta));
   
   g.drawLine(PrevX, PrevY, CurX, CurY);
   
   PrevX=CurX;
   PrevY=CurY;
  }
   //подпишем оси, значения...
  g.setColor(Color.red);
      
  g.drawString("-2Pi",Convert_X(-2*Pi)-(int)(curFontMetrics.stringWidth("-2Pi")/2),
		Convert_Y(-0.06)+curFontMetrics.getHeight());
  g.drawString("-Pi",Convert_X(-Pi)-(int)(curFontMetrics.stringWidth("-Pi")/2),
		Convert_Y(-0.06)+curFontMetrics.getHeight());
  g.drawString("Pi",Convert_X(Pi)-(int)(curFontMetrics.stringWidth("Pi")/2),
		Convert_Y(-0.06)+curFontMetrics.getHeight());
  g.drawString("2Pi",Convert_X(2*Pi)-(int)(curFontMetrics.stringWidth("2Pi")/2),
		Convert_Y(-0.06)+curFontMetrics.getHeight());
  
  g.drawString("-1",Convert_X(0.1),Convert_Y(-1)+(int)(curFont.getSize()/2));
  g.drawString("1",Convert_X(0.1),Convert_Y(1)+(int)(curFont.getSize()/2));
  g.drawString("0",Convert_X(0.1),Convert_Y(0)+curFont.getSize());
  
  g.setColor(Color.yellow);

  g.drawString("x",Convert_X(5*Pi/2)-15,Convert_Y(0)+curFont.getSize()+5);
  g.drawString("y",Convert_X(0)+5,Convert_Y(1.5)+curFont.getSize());
  g.drawString("Y=SIN(X)",Convert_X(Pi)+5,Convert_Y(1.1)+curFont.getSize());
 }
}


Компилируем, запускаем, смотрим. У меня получилось что-то такое:

Приложение PaintApp


Автор: Vitaly
Hosted by uCoz